const EventEmitter = require('events')

function getTimeStrings({curHour, curMin, curSec, lenHour, lenMin, lenSec}) {
  // Multiplication casts to numbers; addition prioritizes strings.
  // Thanks, JavaScript!
  const curSecTotal = (3600 * curHour) + (60 * curMin) + (1 * curSec)
  const lenSecTotal = (3600 * lenHour) + (60 * lenMin) + (1 * lenSec)
  const percentVal = (100 / lenSecTotal) * curSecTotal
  const percentDone = (
    (Math.trunc(percentVal * 100) / 100).toFixed(2) + '%'
  )

  const leftSecTotal = lenSecTotal - curSecTotal
  let leftHour = Math.floor(leftSecTotal / 3600)
  let leftMin = Math.floor((leftSecTotal - leftHour * 3600) / 60)
  let leftSec = Math.floor(leftSecTotal - leftHour * 3600 - leftMin * 60)

  const pad = val => val.toString().padStart(2, '0')
  curMin = pad(curMin)
  curSec = pad(curSec)
  lenMin = pad(lenMin)
  lenSec = pad(lenSec)
  leftMin = pad(leftMin)
  leftSec = pad(leftSec)

  // We don't want to display hour counters if the total length is less
  // than an hour.
  let timeDone, timeLeft, duration
  if (parseInt(lenHour) > 0) {
    timeDone = `${curHour}:${curMin}:${curSec}`
    timeLeft = `${leftHour}:${leftMin}:${leftSec}`
    duration = `${lenHour}:${lenMin}:${lenSec}`
  } else {
    timeDone = `${curMin}:${curSec}`
    timeLeft = `${leftMin}:${leftSec}`
    duration = `${lenMin}:${lenSec}`
  }

  return {percentDone, timeDone, timeLeft, duration, curSecTotal, lenSecTotal}
}

class Player extends EventEmitter {
  constructor() {
    super()

    this.disablePlaybackStatus = false
  }

  playFile(file) {}
  seekAhead(secs) {}
  seekBack(secs) {}
  volUp(amount) {}
  volDown(amount) {}
  togglePause() {}

  async kill() {}

  printStatusLine(data) {
    // Quick sanity check - we don't want to print the status line if it's
    // disabled! Hopefully printStatusLine won't be called in that case, but
    // if it is, we should be careful.
    if (!this.disablePlaybackStatus) {
      this.emit('printStatusLine', data)
    }
  }
}

module.exports.WebPlayer = class extends Player {
  constructor() {
    super()

    const secToMore = time => ({
      hour: Math.floor(time / 3600),
      min: Math.floor((time % 3600) / 60),
      sec: Math.floor(time % 60)
    })

    setInterval(() => {
      if (!this.audioEl) return

      const { hour: curHour, min: curMin, sec: curSec } = secToMore(this.audioEl.currentTime)
      const { hour: lenHour, min: lenMin, sec: lenSec } = secToMore(this.audioEl.duration)

      this.printStatusLine(getTimeStrings({
        curHour, curMin, curSec,
        lenHour, lenMin, lenSec
      }))
    }, 50)
  }

  playFile(file) {
    this.audioEl = document.createElement('audio')
    this.audioEl.src = file
    this.audioEl.play()

    return Promise.race([
      new Promise(resolve => this.stopPromise = resolve),
      new Promise(resolve => {
        const handleEnded = () => {
          this.audioEl.removeEventListener('ended', handleEnded)
          resolve()
        }

        this.audioEl.addEventListener('ended', handleEnded)
      })
    ])
  }

  seekAhead(secs) {
    if (!this.audioEl) return
    this.audioEl.currentTime += secs
  }

  seekBack(secs) {
    if (!this.audioEl) return
    this.audioEl.currentTime -= secs
  }

  togglePause() {
    if (!this.audioEl) return
    if (this.audioEl.paused) {
      this.audioEl.play()
    } else {
      this.audioEl.pause()
    }
  }

  kill() {
    if (!this.audioEl) return
    this.audioEl.currentTime = 0
    this.audioEl.pause()
    if (this.stopPromise) {
      this.stopPromise()
    }
    delete this.audioEl
  }
}

module.exports.getPlayer = async function() {
  return new module.exports.WebPlayer()
}
